package com.ovolucky.mapmytrip.app.place;

import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;

import static com.ovolucky.mapmytrip.app.place.PlaceJsonParser.parse;

/**
 * Created by wanghuifang on 7/12/14.
 */
public class PlaceProvider extends ContentProvider {

  public static final String AUTHORITY = "com.ovolucky.mapmytrip.app.place.PlaceProvider";
  public static final Uri SEARCH_URI = Uri.parse("content://"+AUTHORITY+"/search");
  public static final Uri DETAILS_URI = Uri.parse("content://"+AUTHORITY+"/details");

  private static final int SEARCH = 1;
  private static final int SUGGESTIONS = 2;
  private static final int DETAILS = 3;

  String apiKey = "key=AIzaSyAXAHrxf2v9-rkdHFb2gGF2hGnOOXqlwas";

  // Defines a set of uris allowed with this content provider
  private static final UriMatcher mUriMatcher = buildUriMatcher();

  private static UriMatcher buildUriMatcher() {

    UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    // URI for "Go" button
    uriMatcher.addURI(AUTHORITY, "search", SEARCH );

    // URI for suggestions in Search Dialog
    uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,SUGGESTIONS);

    // URI for Details
    uriMatcher.addURI(AUTHORITY, "details",DETAILS);

    return uriMatcher;
  }

  @Override
  public boolean onCreate() {
    return false;
  }

  @Override
  public Cursor query(Uri uri, String[] projection, String selection,
                      String[] selectionArgs, String sortOrder) {
    Cursor cursor = null;


    String jsonString;
    String jsonPlaceDetails;

    List<HashMap<String, String>> placeList;
    List<HashMap<String, String>> placeDetailList;

    MatrixCursor matrixCursor;

    switch(mUriMatcher.match(uri)){
      case SEARCH:
        // Defining a cursor object with columns description, lat and lng
        matrixCursor = new MatrixCursor(new String[] { "description","lat","lng" });

        // Get Places from Google Places API
        jsonString = getPlaces(selectionArgs);
        try {
          // Parse the places ( JSON => List )
          placeList = parse(new JSONObject(jsonString));

          // Finding latitude and longitude for each places using Google Places Details API
          for(int i=0;i<placeList.size();i++){
            HashMap<String, String> hMap = placeList.get(i);

            // Get Place details
            jsonPlaceDetails = getPlaceDetails(hMap.get("reference"));

            // Parse the details ( JSON => List )
            placeDetailList =
                PlaceDetailsJsonParser.parse(new JSONObject(jsonPlaceDetails));

            // Creating cursor object with places
            for(int j=0;j<placeDetailList.size();j++){
              HashMap<String, String> hMapDetails = placeDetailList.get(j);

              // Adding place details to cursor
              matrixCursor.addRow(new String[]{hMap.get("description"), hMapDetails.get("lat"), hMapDetails.get("lng")});
            }

          }
        } catch (JSONException e) {
          throw new RuntimeException(e);
        }
        cursor = matrixCursor;
        break;

      case SUGGESTIONS :
        // Defining a cursor object with columns id, SUGGEST_COLUMN_TEXT_1, SUGGEST_COLUMN_INTENT_EXTRA_DATA
        matrixCursor = new MatrixCursor(new String[] { "_id", SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA } );

        // Get Places from Google Places API
        jsonString = getPlaces(selectionArgs);

        try {
          // Parse the places ( JSON => List )
          placeList = parse(new JSONObject(jsonString));

          // Creating cursor object with places
          for(int i=0;i<placeList.size();i++){
            HashMap<String, String> hMap = placeList.get(i);

            // Adding place details to cursor
            matrixCursor.addRow(new String[] { Integer.toString(i), hMap.get("description"), hMap.get("reference") });
          }
        } catch (JSONException e) {
          throw new RuntimeException(e);
        }
        cursor = matrixCursor;
        break;

      case DETAILS :
        // Defining a cursor object with columns description, lat and lng
        matrixCursor = new MatrixCursor(new String[] { "description","lat","lng" });

        jsonPlaceDetails = getPlaceDetails(selectionArgs[0]);
        try {
          placeDetailList =
              PlaceDetailsJsonParser.parse(new JSONObject(jsonPlaceDetails));
        } catch (JSONException e) {
          throw new RuntimeException(e);
        }

        for(int j=0;j<placeDetailList.size();j++){
          HashMap<String, String> hMapDetails = placeDetailList.get(j);
          matrixCursor.addRow(new String[]{hMapDetails.get("formatted_address"), hMapDetails.get("lat"), hMapDetails.get("lng")});
        }
        cursor = matrixCursor;
        break;
    }
    return cursor;
  }

  @Override
  public String getType(Uri uri) {
    return null;
  }

  @Override
  public Uri insert(Uri uri, ContentValues contentValues) {
    return null;
  }

  @Override
  public int delete(Uri uri, String s, String[] strings) {
    return 0;
  }

  @Override
  public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
    return 0;
  }

  /** A method to download json data from url */
  private String downloadUrl(String strUrl) throws IOException {
    String data = "";
    InputStream iStream = null;
    HttpURLConnection urlConnection = null;
    try{
      URL url = new URL(strUrl);

      // Creating an http connection to communicate with url
      urlConnection = (HttpURLConnection) url.openConnection();

      // Connecting to url
      urlConnection.connect();

      // Reading data from url
      iStream = urlConnection.getInputStream();

      BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

      StringBuffer sb = new StringBuffer();

      String line;
      while(( line = br.readLine()) != null){
        sb.append(line);
      }

      data = sb.toString();

      br.close();

    }catch(Exception e){
      Log.d("Exception while downloading url", e.toString());
    }finally{
      iStream.close();
      urlConnection.disconnect();
    }
    return data;
  }

  private String getPlaceDetailsUrl(String ref){

    // reference of place
    String reference = "reference="+ref;

    // Sensor enabled
    String sensor = "sensor=false";

    // Building the parameters to the web service
    String parameters = reference + "&" + sensor + "&" + apiKey;

    // Output format
    String output = "json";

    // Building the url to the web service
    String url = "https://maps.googleapis.com/maps/api/place/details/" +
        output + "?" +parameters;

    return url;
  }

  private String getPlacesUrl(String qry){

    try {
      qry = "input=" + URLEncoder.encode(qry, "utf-8");
    } catch (UnsupportedEncodingException e1) {
      e1.printStackTrace();
    }

    // Sensor enabled
    String sensor = "sensor=false";

    // place type to be searched
    String types = "types=geocode";

    // Building the parameters to the web service
    String parameters = qry+"&"+types+"&"+sensor+"&"+ apiKey;

    // Output format
    String output = "json";
    // Building the url to the web service
    String url = "https://maps.googleapis.com/maps/api/place/autocomplete/"+output+"?"+parameters;
    return url;
  }

  private String getPlaces(String[] params){
    // For storing data from web service
    String data = "";
    String url = getPlacesUrl(params[0]);
    try{
      // Fetching the data from web service in background
      data = downloadUrl(url);
    }catch(Exception e){
      Log.d("Background Task", e.toString());
    }
    return data;
  }

  private String getPlaceDetails(String reference){
    String data = "";
    String url = getPlaceDetailsUrl(reference);
    try {
      data = downloadUrl(url);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return data;
  }
}
